package com.naiterui.common.jinshuju.service.impl;

import java.io.UnsupportedEncodingException;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import javax.xml.bind.DatatypeConverter;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.ParameterizedTypeReference;
import org.springframework.http.ResponseEntity;

import com.google.common.collect.Maps;
import com.naiterui.common.jinshuju.bean.JinshujuCallback;
import com.naiterui.common.jinshuju.bean.JinshujuForm;
import com.naiterui.common.jinshuju.bean.JinshujuFormField;
import com.naiterui.common.jinshuju.bean.JinshujuInfo;
import com.naiterui.common.jinshuju.bean.JinshujuQA;
import com.naiterui.common.jinshuju.constants.JinshujuConstants;
import com.naiterui.common.jinshuju.exception.JinshujuException;
import com.naiterui.common.jinshuju.exception.JinshujuExceptionCodes;
import com.naiterui.common.jinshuju.properties.JinshujuProperties;
import com.naiterui.common.jinshuju.service.JinshujuService;
import com.naiterui.common.jinshuju.util.RestHttpUtil;
import com.naiterui.common.redis.RedisUtil;

/**
 * @author gaoliangliang
 * @date 2019/10/17 4:30 下午
 * @since 1.0.0
 */
public class JinshujuServiceImpl implements JinshujuService {

    private static final Logger LOGGER = LoggerFactory.getLogger(JinshujuServiceImpl.class);

    private Map<String, JinshujuProperties.JinshujuConfig> jinshujuConfigStorageMap;

    @Override
    public JinshujuProperties.JinshujuConfig getJinshujuConfigStorage(String uid) {
        return jinshujuConfigStorageMap.getOrDefault(uid, new JinshujuProperties.JinshujuConfig());
    }

    @Override
    public void setJinshujuConfigStorage(Map<String, JinshujuProperties.JinshujuConfig> jinshujuConfigStorageMap) {
        this.jinshujuConfigStorageMap = jinshujuConfigStorageMap;
    }

    @Override
    public JinshujuInfo convertToInfo(JinshujuCallback jinshujuCallback) throws JinshujuException {

        JinshujuForm jinshujuForm = this.getAndFlushForm(jinshujuCallback.getUid(), jinshujuCallback.getFormId());
        LOGGER.debug("jinshujuForm = {}", jinshujuForm);
        Map<String, Object> entry = jinshujuCallback.getEntry();

        Map<String, JinshujuFormField> formFieldMap = new HashMap<>();
        jinshujuForm.getFields().forEach(formFieldMap::putAll);

        List<JinshujuQA> qaList = entry.keySet().stream().filter(key -> key.startsWith(JinshujuConstants.JINSHUJU_ENTRY_KEY))
                                       .map(fieldKey -> {
                                           JinshujuFormField field = formFieldMap.get(fieldKey);
                                           String question = JinshujuConstants.QuestType.other.getTypeDesc();
                                           JinshujuConstants.QuestType qType = JinshujuConstants.QuestType.other;
                                           if (field != null) {
                                               question = field.getLabel();
                                               qType = JinshujuConstants.QuestType.byTypeStr(field.getType());
                                           }
                                           JinshujuQA jinshujuQA = new JinshujuQA(fieldKey, question);
                                           jinshujuQA.setType(qType.getType());
                                           Object answer = entry.get(fieldKey);
                                           answer = answer == null ? "" : answer;
                                           if (answer instanceof Map) {
                                               answer = ((Map) answer).values().stream().map(Object::toString).collect(Collectors.joining("\t"));
                                           }
                                           jinshujuQA.setAnswers(Collections.singletonList(answer.toString()));
                                           return jinshujuQA;
                                       }).collect(Collectors.toList());

        LOGGER.debug("qaList {}", qaList);

        return JinshujuInfo.builder()
                           .uid(jinshujuCallback.getUid())
                           .formId(jinshujuCallback.getFormId())
                           .formName(jinshujuCallback.getFormName())
                           .serialNumber(entry.getOrDefault(JinshujuConstants.SERIAL_NUMBER_KEY, "").toString())
                           .bizId(jinshujuCallback.getBizId())
                           .openId(jinshujuCallback.getOpenId())
                           .qaList(qaList)
                           .build();
    }

    @Override
    public JinshujuForm getAndFlushForm(String uid, String formId) throws JinshujuException {

        String cacheKey = JinshujuConstants.JINSHUJU_FORMCACHE_PREFIX + formId;
        JinshujuForm jinshujuFormCache = (JinshujuForm) RedisUtil.valueOps().getObject(cacheKey);
        if (jinshujuFormCache != null) {
            LOGGER.info("缓存中获取量表表单:{}", formId);
            return jinshujuFormCache;
        }

        JinshujuProperties.JinshujuConfig configStorage = this.getJinshujuConfigStorage(uid);
        String jinshujuKey = configStorage.getApikey();
        String jinshujuSecret = configStorage.getApisecret();
        String requestUrl = configStorage.getApidomain() + formId;
        String authStr = jinshujuKey + ":" + jinshujuSecret;
        int cacheExpire = configStorage.getCacheExpire();
        String encoding = null;
        try {
            encoding = DatatypeConverter.printBase64Binary(authStr.getBytes(JinshujuConstants.DEFAULT_CHARSET));
        } catch (UnsupportedEncodingException e) {
            LOGGER.error("jinshuju get form error ; formId={}", formId, e);
            throw new JinshujuException(JinshujuExceptionCodes.GET_FORM_UNKUNOW_ERROR);
        }

        Map<String, String> requestHeader = Maps.newHashMap();
        requestHeader.put("Authorization", "Basic " + encoding);
        ResponseEntity<JinshujuForm> requestEntity = RestHttpUtil
                .get()
                .url(requestUrl)
                .header(requestHeader)
                .execute(new ParameterizedTypeReference<JinshujuForm>() {
                });

        if (requestEntity == null || requestEntity.getBody() == null) {
            LOGGER.error("jinshuju get form error : request result empty ; formId={}", formId);
            throw new JinshujuException(JinshujuExceptionCodes.GET_FORM_UNKUNOW_ERROR);
        }
        JinshujuForm jinshujuFormRemote = requestEntity.getBody();
        jinshujuFormRemote.setForm(formId);

        // MongoDB存储
        //redis存储
        RedisUtil.valueOps().set(cacheKey, jinshujuFormRemote, cacheExpire);
        return jinshujuFormRemote;
    }
}
